﻿using GameProtocol.Protocol;
using Google.Protobuf;
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;

namespace GameLogic
{
    public class TCPServer : NetServer
    {
        Socket m_Socket;
        byte[] m_ReceiveData = new byte[1500];

        public override void Init(int receivePort = 24567, int sendPort = 24568)
        {
            base.Init(receivePort, sendPort);
            m_Socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            m_Socket.Bind(new IPEndPoint(IPAddress.Any, m_ReceivePort));
            m_Socket.Listen(10);
            Listen();
        }

        protected override void Send(IPEndPoint endPoint, byte[] data, int length)
        {
            var ip = endPoint.Address.ToString();
            if (ip == IPAddress.Broadcast.ToString())
            {
                foreach (var i in m_ClientHandleMap)
                {
                    i.Value.Send(data, length);
                }
            }
            else if (m_ClientHandleMap.ContainsKey(ip))
            {
                m_ClientHandleMap[ip].Send(data, length);
            }
        }
        public override void Send(GameProtocol.Protocol.CSMsgId id, IPEndPoint ep, byte[] data)
        {
            MessageContent content = new MessageContent();
            if (data != null)
                content.Data = ByteString.CopyFrom(data);

            content.MsgID = id;

            var length = GlobalFunction.PlusLengthHeadToByteArray(m_SendDataBuffer, content.ToByteArray());
            Send(new IPEndPoint(IPAddress.Broadcast, m_SendPort), m_SendDataBuffer, length);
        }
         protected override void OnReceived(IPEndPoint ep, byte[] data, int curOffset, int length)
        {
            base.OnReceived(ep, data, curOffset, length);
            try
            {
                var msg = MessageContent.Parser.ParseFrom(data, curOffset, length);
                if (msg != null && m_ReceiveEvents.ContainsKey(msg.MsgID))
                {
                    var subData = msg.Data.ToByteArray();
                    var rspData = ConnectRspData.Parser.ParseFrom(subData);
                    if (rspData != null && msg.MsgID == CSMsgId.ConnectRsp)
                    {
                        OnHandshakeSuccess(ep.Address.ToString());
                        UnityEngine.Debug.Log("服务器牵手成功！");
                    }
                    m_ReceiveEvents[msg.MsgID].Invoke((IPEndPoint)ep, subData);
                }
            }
            catch (Exception e)
            {
                UnityEngine.Debug.LogError(e.ToString());
            }
        }
        async void DoReceive(TCPClientHandle handle)
        {
            await Task.Run(() =>
            {
                var length = handle.Socket.Receive(handle.Data);
                if(length > 1024)
                {
                    UnityEngine.Debug.LogError("数据包爆炸了");
                }
                if (length > 0)
                {
                    var curOffset = 0;
                    var curLength = length;
                    var packageLength = 0;

                    packageLength = BitConverter.ToUInt16(handle.Data, curOffset);
                    if(packageLength + 2 > length)
                    {
                        UnityEngine.Debug.LogWarning("粘包咯！");
                    }
                    while (curLength >= packageLength + 2)
                    {// 解决粘包问题
                        if (handle.HasHandShake == false)
                        {
                            handle.HasHandShake = true;
                            ResponHandShake(handle.Data, curOffset + 2, packageLength, (IPEndPoint)handle.Socket.RemoteEndPoint);
                        }
                        OnReceived((IPEndPoint)handle.Socket.RemoteEndPoint, handle.Data, curOffset + 2, packageLength);
                        curOffset += packageLength + 2;
                        curLength -= packageLength + 2;
                        packageLength = BitConverter.ToUInt16(handle.Data, curOffset);
                    }

                }
                else
                {
                    UnityEngine.Debug.LogError("收到数据异常大小 = " + length);
                }
            });
            DoReceive(handle);
        }

        void ResponHandShake(byte[] data, int offset, int length, IPEndPoint endPoint)
        {

            GameProtocol.Protocol.MessageContent messageContent = GameProtocol.Protocol.MessageContent.Parser.ParseFrom(data, offset, length);
            if (messageContent != null && messageContent.MsgID == CSMsgId.ConnectRqr)
            {
                var rqrData = ConnectRqrData.Parser.ParseFrom(messageContent.Data);
                if (rqrData != null)
                {
                    var rspData = new ConnectRspData();
                    rspData.ConversationID = rqrData.ConversationID;

                    Send(CSMsgId.ConnectRsp, endPoint, rspData.ToByteArray());
                    var ip = endPoint.Address.ToString();
                    m_ClientHandleMap[ip].HasHandShake = true;
                }
            }
        }
        protected override void OnClientTimeout(ClientHandle clientHand)
        {
            base.OnClientTimeout(clientHand);
        }

        async void Listen()
        {
            await Task.Run(() =>
            {
                var handle = m_Socket.Accept();
                var ep = (IPEndPoint)handle.RemoteEndPoint;
                var ip = ep.Address.ToString();
                TCPClientHandle clientHandle = TCPClientHandle.Create(handle);
                if (!m_ClientHandleMap.ContainsKey(ip))
                    m_ClientHandleMap.TryAdd(ip, clientHandle);
                else
                {
                    m_ClientHandleMap[ip].Close();
                    m_ClientHandleMap[ip] = clientHandle;
                }
                m_ClientHandleMap[ip].IP = ip;
                m_ClientHandleMap[ip].TimeoutCallback = OnClientTimeout;
                DoReceive(clientHandle);
            });
            Listen();
        }
    }
}

